package com.qinglei.recoup.longconn.service.impl;

import com.qinglei.recoup.common.domain.CommonConstant;
import com.qinglei.recoup.common.domain.RadarFallDownDataDTO;
import com.qinglei.recoup.common.domain.RadarMessage;
import com.qinglei.recoup.common.domain.RadarUserDataDTO;
import com.qinglei.recoup.common.utils.DateUtil;
import com.qinglei.recoup.longconn.constant.LongConnConstant;
import com.qinglei.recoup.longconn.entity.*;
import com.qinglei.recoup.longconn.server.DeviceNettyServer;
import com.qinglei.recoup.longconn.service.FileService;
import com.qinglei.recoup.longconn.service.MessageProcService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.List;

@Service
@Slf4j
//@Scope("prototype")
public class MessageProcServiceImpl implements MessageProcService {
    @Resource
    private FileService fileService;

    @Resource
    private DeviceNettyServer deviceNettyServer;

    @Resource
    RabbitTemplate rabbitTemplate;

    @Value("${spring.rabbitmq.host:}")
    private String rabbitmqHost;

    @EventListener
    @Async
    public void uploadDataEventListener(UploadDataEvent event) {
        log.debug("uploadDataEventListener event: {}", event);
        try {
            this.procUploadDataMessage(event.getMessage());
        } catch (Exception e) {
            log.error("uploadDataEventListener error", e);
        }
    }

    @EventListener
    @Async
    public void sendRadarDataEventListener(SendRadarDataEvent event) {
        log.debug("sendRadarDataEventListener event: {}", event);
        try {
            this.procRadarStatus(event.getMessage());
        } catch (Exception e) {
            log.error("sendRadarDataEventListener error", e);
        }
    }

    /**
     * 发送消息到消息队列
     *
     * @param radarMessage
     */
    private void sendMessage2MQ(RadarMessage radarMessage) {
        if (StringUtils.isNotEmpty(rabbitmqHost)) {
            log.debug("sendMessage2MQ radarMessage: {}", radarMessage);
            rabbitTemplate.convertAndSend(CommonConstant.MQ_RECOUP_DIRECT_EXCHANGE, CommonConstant.MQ_RADAR_DATA_ROUTING, radarMessage);
        }
    }

    /**
     * 发送下行消息给所有客户端
     *
     * @param funcCode
     * @param body
     * @return
     */
    @Override
    public int sendMessageAllClient(String funcCode, String body) {
        return deviceNettyServer.sendMessageAllClient(funcCode, body);
    }

    /**
     * 发送下行消息给所有客户端
     *
     * @param funcCode
     * @param body
     * @return
     */
    @Override
    public int sendMessage2Client(List<String> snList, String funcCode, String body) {
        return deviceNettyServer.sendMessage2Client(snList, funcCode, body);
    }

    /**
     * 处理用户数据消息
     *
     * @param message
     */
    @Override
    public void procUploadDataMessage(Message message) {
        // 保存文件
        fileService.save(message);
        if (message.getProjectCode() == LongConnConstant.PROJECT_CODE_BREATH_HEART) {
            // 处理呼吸心跳数据
            this.procBreathHeartData(message);
        } else if (message.getProjectCode() == LongConnConstant.PROJECT_CODE_FALL_DOWN) {
            // 处理跌倒数据
            this.procFallDownData(message);
        } else {
            log.warn("procUploadDataMessage not support project code,message:{}", message);
        }
    }

    /**
     * 处理呼吸心跳数据
     *
     * @param message
     */
    private void procBreathHeartData(Message message) {
        // 如果是雷达用户数据，发送消息给WEB服务
        if (message.getFuncCode().equals(LongConnConstant.FUNC_UP_USER_DATA)) {
            RadarMessage radarMessage = new RadarMessage();
            radarMessage.setProCode("3_0");  //3.0雷达数据
            radarMessage.setSn(message.getSn());
            radarMessage.setType(RadarMessage.TYPE_USER_DATA);
            RadarUserDataDTO radarUserDataDTO = new RadarUserDataDTO();
            BeanUtils.copyProperties(message.getBody(), radarUserDataDTO);

            radarMessage.setData(radarUserDataDTO);
            LocalDateTime dateTime = LocalDateTime.parse(message.getTimestamp(),
                    DateTimeFormatter.ofPattern(DateUtil.FULL_TIME_MILLI_BAR_PATTERN));
            long milliSecond = dateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
            radarMessage.setTimestamp(milliSecond);
            // 发送消息到MQ
            sendMessage2MQ(radarMessage);
        }
    }

    /**
     * 处理跌倒数据
     *
     * @param message
     */
    private void procFallDownData(Message message) {
        // 如果是雷达用户数据，发送消息给WEB服务
        RadarMessage radarMessage = new RadarMessage();
        radarMessage.setSn(message.getSn());
        radarMessage.setType(RadarMessage.TYPE_FALL_DOWN_DATA);
        RadarFallDownDataDTO radarFallDownDataDTO = new RadarFallDownDataDTO();
        FallDownUserDataBody fallDownUserDataBody = (FallDownUserDataBody) message.getBody();
        // 判断是否有人
        int exist = 0;
        for (int i : fallDownUserDataBody.getExist()) {
            exist |= i;
        }
        if (exist > 0) {
            radarFallDownDataDTO.setExist(1);
        }
        // 判断是否跌倒
        int fall = 0;
        for (int i : fallDownUserDataBody.getL2()) {
            fall |= i;
        }
        if (fall > 0) {
            radarFallDownDataDTO.setL2(1);
        }
        radarMessage.setData(radarFallDownDataDTO);
        radarMessage.setProCode("3_0");  //3.0雷达数据
        LocalDateTime dateTime = LocalDateTime.parse(message.getTimestamp(),
                DateTimeFormatter.ofPattern(DateUtil.FULL_TIME_MILLI_BAR_PATTERN));
        long milliSecond = dateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
        radarMessage.setTimestamp(milliSecond);
        // 发送消息到MQ
        sendMessage2MQ(radarMessage);
    }

    /**
     * 处理雷达事件
     *
     * @param message
     */
    @Override
    public void procRadarStatus(RadarMessage message) {
        // 发送消息到MQ
        sendMessage2MQ(message);
        // 清理设备数据
//        if (message.getType() == RadarMessage.TYPE_DEVICE_STATUS
//                && (int) message.getData() == RadarMessage.STATUS_OFFLINE) {
//            fileService.procDeviceOffline(message.getSn());
//        }
    }
}
